using MicroMsg.Common.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Media.Imaging;
namespace MicroMsg.UI.UserContrl
{
	public class GifDecoder
	{
		private const string TAG = "MicroMsg.GifDecoder";
		public const int STATUS_FORMAT_ERROR = -1;
		public const int STATUS_FINISH = 0;
		private const int MaxStackSize = 4096;
		private Stream stream;
		private int status;
		private bool gctFlag;
		private int gctSize;
		public int width;
		public int height;
		private int[] int_0;
		private int[] int_1;
		private int[] int_2;
		private int bgIndex;
		private int bgColor;
		private int lastBgColor;
		private bool lctFlag;
		private bool interlace;
		private int lctSize;
		private int int_3;
		private int int_4;
		private int int_5;
		private int int_6;
		private int int_7;
		private int int_8;
		private int int_9;
		private int int_10;
		private byte[] block = new byte[256];
		private int blockSize;
		private int dispose;
		private int lastDispose;
		private bool transparency;
		private int delay;
		private int transIndex;
		private short[] prefix;
		private byte[] suffix;
		private byte[] pixelStack;
		private byte[] pixels;
		private List<GifFrame> frames = new List<GifFrame>();
		public GifDecoder(Stream stream)
		{
			this.stream = stream;
		}
		public int decode(List<GifFrame> frames)
		{
			this.frames = frames;
			this.init();
			this.readHeader();
			if (this.isErr())
			{
				return -1;
			}
			this.readContents();
			if (!this.isErr())
			{
				return 0;
			}
			return -1;
		}
		private bool isErr()
		{
			return this.status != 0;
		}
		private void init()
		{
			this.status = 0;
			this.int_0 = null;
			this.int_1 = null;
		}
		private void readHeader()
		{
			string text = "";
			for (int i = 0; i < 6; i++)
			{
				text += (char)this.readByte();
			}
			if (!text.StartsWith("GIF"))
			{
				this.status = -1;
				return;
			}
			this.readLSD();
			if (this.gctFlag && !this.isErr())
			{
				this.int_0 = this.readColorTable(this.gctSize);
				this.bgColor = this.int_0[this.bgIndex];
			}
		}
		private void readContents()
		{
			bool flag = false;
			while (!flag && !this.isErr())
			{
				int num = this.readByte();
				int num2 = num;
				if (num2 <= 33)
				{
					if (num2 == 0)
					{
						Log.smethod_5("MicroMsg.GifDecoder", "notice, bad byte!");
						continue;
					}
					if (num2 == 33)
					{
						num = this.readByte();
						int num3 = num;
						if (num3 == 249)
						{
							this.readGraphicControlExt();
							continue;
						}
						if (num3 != 255)
						{
							this.skip();
							continue;
						}
						this.readBlock();
						string text = "";
						for (int i = 0; i < 11; i++)
						{
							text += (char)this.block[i];
						}
						if (text == "NETSCAPE2.0")
						{
							this.readNetscapeExt();
							continue;
						}
						this.skip();
						continue;
					}
				}
				else
				{
					if (num2 == 44)
					{
						this.readImage();
						continue;
					}
					if (num2 == 59)
					{
						flag = true;
						continue;
					}
				}
				this.status = -1;
			}
		}
		private void readLSD()
		{
			this.width = this.readShort();
			this.height = this.readShort();
			int num = this.readByte();
			this.gctFlag = ((num & 128) != 0);
			this.gctSize = 2 << (num & 7);
			this.bgIndex = this.readByte();
			this.readByte();
		}
		private int[] readColorTable(int ncolors)
		{
			int num = 3 * ncolors;
			int[] array = null;
			byte[] array2 = new byte[num];
			int num2 = 0;
			try
			{
				num2 = this.stream.Read(array2, 0, num);
			}
			catch (Exception ex)
			{
				Log.smethod_1("MicroMsg.GifDecoder", ex.ToString());
			}
			if (num2 < num)
			{
				this.status = -1;
			}
			else
			{
				array = new int[256];
				int i = 0;
				int num3 = 0;
				while (i < ncolors)
				{
					int num4 = (int)(array2[num3++] & 255);
					int num5 = (int)(array2[num3++] & 255);
					int num6 = (int)(array2[num3++] & 255);
					array[i++] = (-16777216 | num4 << 16 | num5 << 8 | num6);
				}
			}
			return array;
		}
		private void readImage()
		{
			this.int_3 = this.readShort();
			this.int_4 = this.readShort();
			this.int_5 = this.readShort();
			this.int_6 = this.readShort();
			int num = this.readByte();
			this.lctFlag = ((num & 128) != 0);
			this.interlace = ((num & 64) != 0);
			this.lctSize = 2 << (num & 7);
			if (this.lctFlag)
			{
				this.int_1 = this.readColorTable(this.lctSize);
				this.int_2 = this.int_1;
			}
			else
			{
				this.int_2 = this.int_0;
				if (this.bgIndex == this.transIndex)
				{
					this.bgColor = 0;
				}
			}
			int num2 = 0;
			if (this.transparency)
			{
				num2 = this.int_2[this.transIndex];
				this.int_2[this.transIndex] = 0;
			}
			if (this.int_2 == null)
			{
				this.status = -1;
			}
			if (this.isErr())
			{
				return;
			}
			this.decodeImageData();
			this.skip();
			if (this.isErr())
			{
				return;
			}
			this.frames.Add(new GifFrame(this.setPixels(), this.delay));
			if (this.transparency)
			{
				this.int_2[this.transIndex] = num2;
			}
			this.resetFrame();
		}
		private void decodeImageData()
		{
			int num = -1;
			int num2 = this.int_5 * this.int_6;
			if (this.pixels == null || this.pixels.Length < num2)
			{
				this.pixels = new byte[num2];
			}
			if (this.prefix == null)
			{
				this.prefix = new short[4096];
			}
			if (this.suffix == null)
			{
				this.suffix = new byte[4096];
			}
			if (this.pixelStack == null)
			{
				this.pixelStack = new byte[4097];
			}
			int num3 = this.readByte();
			int num4 = 1 << num3;
			int num5 = num4 + 1;
			int num6 = num4 + 2;
			int num7 = num;
			int num8 = num3 + 1;
			int num9 = (1 << num8) - 1;
			for (int i = 0; i < num4; i++)
			{
				this.prefix[i] = 0;
				this.suffix[i] = (byte)i;
			}
			int num16;
			int num15;
			int num14;
			int num13;
			int num12;
			int num11;
			int num10 = num11 = (num12 = (num13 = (num14 = (num15 = (num16 = 0)))));
			for (int j = 0; j < num2; j++)
			{
				if (num14 == 0)
				{
					if (num10 < num8)
					{
						if (num12 == 0)
						{
							num12 = this.readBlock();
							if (num12 <= 0)
							{
								break;
							}
							num16 = 0;
						}
						num11 += (int)(this.block[num16] & 255) << num10;
						num10 += 8;
						num16++;
						num12--;
						continue;
					}
					int i = num11 & num9;
					num11 >>= num8;
					num10 -= num8;
					if (i > num6 || i == num5)
					{
						break;
					}
					if (i == num4)
					{
						num8 = num3 + 1;
						num9 = (1 << num8) - 1;
						num6 = num4 + 2;
						num7 = num;
						continue;
					}
					if (num7 == num)
					{
						this.pixelStack[num14++] = this.suffix[i];
						num7 = i;
						num13 = i;
						continue;
					}
					int num17 = i;
					if (i == num6)
					{
						this.pixelStack[num14++] = (byte)num13;
						i = num7;
					}
					while (i > num4)
					{
						this.pixelStack[num14++] = this.suffix[i];
						i = (int)this.prefix[i];
					}
					num13 = (int)(this.suffix[i] & 255);
					if (num6 >= 4096)
					{
						break;
					}
					this.pixelStack[num14++] = (byte)num13;
					this.prefix[num6] = (short)num7;
					this.suffix[num6] = (byte)num13;
					num6++;
					if ((num6 & num9) == 0 && num6 < 4096)
					{
						num8++;
						num9 += num6;
					}
					num7 = num17;
				}
				num14--;
				this.pixels[num15++] = this.pixelStack[num14];
			}
			for (int j = num15; j < num2; j++)
			{
				this.pixels[j] = 0;
			}
		}
		private WriteableBitmap setPixels()
		{
			int[] array = new int[this.width * this.height];
			WriteableBitmap writeableBitmap = null;
			if (this.frames.get_Count() > 0)
			{
				writeableBitmap = this.frames.get_Item(this.frames.get_Count() - 1).bitmap;
			}
			if (this.lastDispose > 0)
			{
				if (this.lastDispose == 3)
				{
					if (this.frames.get_Count() > 1)
					{
						writeableBitmap = this.frames.get_Item(this.frames.get_Count() - 2).bitmap;
					}
					else
					{
						writeableBitmap = null;
					}
				}
				if (writeableBitmap != null)
				{
					Array.Copy(writeableBitmap.get_Pixels(), array, writeableBitmap.get_Pixels().Length);
					if (this.lastDispose == 2)
					{
						int num = 0;
						if (!this.transparency)
						{
							num = this.lastBgColor;
						}
						for (int i = 0; i < this.int_10; i++)
						{
							int num2 = (this.int_8 + i) * this.width + this.int_7;
							int num3 = num2 + this.int_9;
							for (int j = num2; j < num3; j++)
							{
								array[j] = num;
							}
						}
					}
				}
			}
			int num4 = 1;
			int num5 = 8;
			int num6 = 0;
			for (int k = 0; k < this.int_6; k++)
			{
				int num7 = k;
				if (this.interlace)
				{
					if (num6 >= this.int_6)
					{
						num4++;
						switch (num4)
						{
						case 2:
							num6 = 4;
							break;
						case 3:
							num6 = 2;
							num5 = 4;
							break;
						case 4:
							num6 = 1;
							num5 = 2;
							break;
						}
					}
					num7 = num6;
					num6 += num5;
				}
				num7 += this.int_4;
				if (num7 < this.height)
				{
					int num8 = num7 * this.width;
					int l = num8 + this.int_3;
					int num9 = l + this.int_5;
					if (num8 + this.width < num9)
					{
						num9 = num8 + this.width;
					}
					int num10 = k * this.int_5;
					while (l < num9)
					{
						int num11 = (int)(this.pixels[num10++] & 255);
						int num12 = this.int_2[num11];
						if (num12 != 0)
						{
							array[l] = num12;
						}
						l++;
					}
				}
			}
			return this.toBitmap(array, this.width, this.height);
		}
		private WriteableBitmap toBitmap(int[] pixels, int width, int height)
		{
			WriteableBitmap writeableBitmap = new WriteableBitmap(width, height);
			if (pixels != null)
			{
				int[] array = writeableBitmap.get_Pixels();
				if (array != null)
				{
					Array.Copy(pixels, array, pixels.Length);
				}
			}
			writeableBitmap.Invalidate();
			return writeableBitmap;
		}
		private void readGraphicControlExt()
		{
			this.readByte();
			int num = this.readByte();
			this.dispose = (num & 28) >> 2;
			if (this.dispose == 0)
			{
				this.dispose = 1;
			}
			this.transparency = ((num & 1) != 0);
			this.delay = this.readShort() * 10;
			this.transIndex = this.readByte();
			this.readByte();
		}
		private void readNetscapeExt()
		{
			do
			{
				this.readBlock();
			}
			while (this.blockSize > 0 && !this.isErr());
		}
		private void resetFrame()
		{
			this.lastDispose = this.dispose;
			this.int_7 = this.int_3;
			this.int_8 = this.int_4;
			this.int_9 = this.int_5;
			this.int_10 = this.int_6;
			this.lastBgColor = this.bgColor;
			this.dispose = 0;
			this.transparency = false;
			this.delay = 0;
			this.int_1 = null;
		}
		private void skip()
		{
			do
			{
				this.readBlock();
			}
			while (this.blockSize > 0 && !this.isErr());
		}
		private int readByte()
		{
			int result = 0;
			try
			{
				result = this.stream.ReadByte();
			}
			catch (Exception)
			{
				this.status = -1;
			}
			return result;
		}
		private int readShort()
		{
			return this.readByte() | this.readByte() << 8;
		}
		private int readBlock()
		{
			this.blockSize = this.readByte();
			int i = 0;
			if (this.blockSize > 0)
			{
				try
				{
					while (i < this.blockSize)
					{
						int num = this.stream.Read(this.block, i, this.blockSize - i);
						if (num == -1)
						{
							break;
						}
						i += num;
					}
				}
				catch (Exception ex)
				{
					Log.smethod_1("MicroMsg.GifDecoder", ex.ToString());
				}
				if (i < this.blockSize)
				{
					this.status = -1;
				}
			}
			return i;
		}
	}
}
